package cn.tlb.gl.texture_3d;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.opengl.GLSurfaceView.Renderer;
import android.opengl.GLUtils;
import android.view.GestureDetector;
import android.view.MotionEvent;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;

import cn.tlb.xutilsdownload.R;

/**
 * Created by 汤林冰 on 2015/12/9 17:18.
 */
public class Renderer_3D implements Renderer, GestureDetector.OnGestureListener{

    float[] vertices = {
            -0.6f, -0.6f, -0.6f, -0.6f, 0.6f,
            -0.6f, 0.6f, 0.6f, -0.6f, 0.6f, 0.6f, -0.6f, 0.6f, -0.6f, -0.6f,
            -0.6f, -0.6f, -0.6f, -0.6f, -0.6f, 0.6f, 0.6f, -0.6f, 0.6f, 0.6f,
            0.6f, 0.6f, 0.6f, 0.6f, 0.6f, -0.6f, 0.6f, 0.6f, -0.6f, -0.6f,
            0.6f, -0.6f, -0.6f, -0.6f, 0.6f, -0.6f, -0.6f, 0.6f, -0.6f, 0.6f,
            0.6f, -0.6f, 0.6f, -0.6f, -0.6f, 0.6f, -0.6f, -0.6f, -0.6f, 0.6f,
            -0.6f, -0.6f, 0.6f, 0.6f, -0.6f, 0.6f, 0.6f, 0.6f, 0.6f, 0.6f,
            0.6f, 0.6f, -0.6f, 0.6f, 0.6f, -0.6f, -0.6f, 0.6f, 0.6f, -0.6f,
            -0.6f, 0.6f, -0.6f, -0.6f, 0.6f, 0.6f, -0.6f, 0.6f, 0.6f, 0.6f,
            0.6f, 0.6f, 0.6f, 0.6f, -0.6f, -0.6f, 0.6f, -0.6f, -0.6f, -0.6f,
            -0.6f, -0.6f, -0.6f, 0.6f, -0.6f, -0.6f, 0.6f, -0.6f, 0.6f, 0.6f,
            -0.6f, 0.6f, -0.6f
    };
    private byte[] cubeFacets = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
            13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
            30, 31, 32, 33, 34, 35, };


    float[] texture = {
            1.0000f, 1.0000f, 1.0000f, 0.0000f,
            0.0000f, 0.0000f, 0.0000f, 0.0000f, 0.0000f, 1.0000f, 1.0000f,
            1.0000f, 0.0000f, 1.0000f, 1.0000f, 1.0000f, 1.0000f, 0.0000f,
            1.0000f, 0.0000f, 0.0000f, 0.0000f, 0.0000f, 1.0000f, 0.0000f,
            1.0000f, 1.0000f, 1.0000f, 1.0000f, 0.0000f, 1.0000f, 0.0000f,
            0.0000f, 0.0000f, 0.0000f, 1.0000f, 0.0000f, 1.0000f, 1.0000f,
            1.0000f, 1.0000f, 0.0000f, 1.0000f, 0.0000f, 0.0000f, 0.0000f,
            0.0000f, 1.0000f, 0.0000f, 1.0000f, 1.0000f, 1.0000f, 1.0000f,
            0.0000f, 1.0000f, 0.0000f, 0.0000f, 0.0000f, 0.0000f, 1.0000f,
            0.0000f, 1.0000f, 1.0000f, 1.0000f, 1.0000f, 0.0000f, 1.0000f,
            0.0000f, 0.0000f, 0.0000f, 0.0000f, 1.0000f
    };

    Context context;
    FloatBuffer verticesBuffer;
    ByteBuffer faceBuffer;
    FloatBuffer textureBuffer;
    int textureId = 0;
    GestureDetector detector;
    private float touchX;
    private float touchY;

    public GestureDetector getDetector() {
        return detector;
    }

    public Renderer_3D(Context context) {
        detector = new GestureDetector(context, this);
        this.context = context;
        verticesBuffer = array2FloatBuffer(vertices);
        faceBuffer = ByteBuffer.wrap(cubeFacets);
        textureBuffer = array2FloatBuffer(texture);
    }

    @Override
    public void onSurfaceCreated(GL10 gl, EGLConfig config) {
        gl.glDisable(GL10.GL_DITHER);
        gl.glShadeModel(GL10.GL_SMOOTH);

        gl.glClearColor(0, 0, 0, 0);
        gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_FASTEST);
        gl.glEnable(GL10.GL_DEPTH_TEST);
        gl.glDepthFunc(GL10.GL_LEQUAL);

//        //启用混色
//        gl.glEnable(GL10.GL_BLEND);
//        //设置混色函数
//        gl.glBlendFunc(GL10.GL_ONE, GL10.GL_SRC_COLOR);
        //启用2d纹理贴图
        gl.glEnable(GL10.GL_TEXTURE_2D);
        loadTexture(gl);
    }

    private void loadTexture(GL10 gl) {
        Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), R.drawable.i);

        int[] textures = new int[1];
        gl.glGenTextures(1,textures, 0);
        textureId = textures[0];
        //在为纹理提供图像数据之前，我们必须绑定纹理
        gl.glBindTexture(GL10.GL_TEXTURE_2D, textureId);
        gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_NEAREST);
        gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);
        gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S, GL10.GL_REPEAT);
        gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T, GL10.GL_REPEAT);
        GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0);

        bitmap.recycle();
        bitmap = null;
    }

    @Override
    public void onSurfaceChanged(GL10 gl, int width, int height) {
        gl.glViewport(0, 0, width, height);
        gl.glMatrixMode(GL10.GL_PROJECTION);
        gl.glLoadIdentity();
        float ratio = (float)width/height;
        gl.glFrustumf(-ratio, ratio, -1, 1, 1, 10);
    }

    @Override
    public void onDrawFrame(GL10 gl) {
        gl.glClear(GL10.GL_DEPTH_BUFFER_BIT | GL10.GL_COLOR_BUFFER_BIT);
        gl.glMatrixMode(GL10.GL_MODELVIEW);

        gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
        gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
        gl.glLoadIdentity();

        gl.glTranslatef(0, 0, -2);
        gl.glRotatef(rotateX, 0, 0.2f, 0);
        gl.glRotatef(rotateY, 0.2f, 0, 0);
        gl.glVertexPointer(3, GL10.GL_FLOAT, 0, verticesBuffer);
        gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, textureBuffer);
        gl.glBindTexture(GL10.GL_TEXTURE_2D, textureId);

        // TODO: 2015/12/16 绘制游若干个独立的三角形组成的几何体时, 需要使用GL_TRIANGLES (顶点个数必须为3的整数倍: 1,2,3,4,5,6 ->1,2,3; 4,5,6两个三角形)
        // TODO: 2015/12/16 如果使用 GL_TRIANGLE_STRIP 将绘制三角形条的几何体(顶点数任意, 可复用: 1,2,3,4--> 1,2,3; 2,3,4两个三角形)
        gl.glDrawElements(GL10.GL_TRIANGLES, faceBuffer.remaining(), GL10.GL_UNSIGNED_BYTE, faceBuffer);
        //gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 4);

        gl.glFinish();
        gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
        gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
    }

    private FloatBuffer array2FloatBuffer(float fs[]){
        ByteBuffer byteBuffer = ByteBuffer.allocateDirect(fs.length * 4);
        byteBuffer.order(ByteOrder.nativeOrder());
        FloatBuffer floatBuffer = byteBuffer.asFloatBuffer();
        floatBuffer.put(fs);
        floatBuffer.position(0);
        return floatBuffer;
    }

    private IntBuffer array2IntBuffer(int ints[]){
        ByteBuffer byteBuffer = ByteBuffer.allocateDirect(ints.length*4);
        byteBuffer.order(ByteOrder.nativeOrder());
        IntBuffer intBuffer = byteBuffer.asIntBuffer();
        intBuffer.put(ints);
        intBuffer.position(0);
        return intBuffer;
    }

    @Override
    public boolean onDown(MotionEvent e) {
        return false;
    }

    @Override
    public void onShowPress(MotionEvent e) {

    }

    @Override
    public boolean onSingleTapUp(MotionEvent e) {
        return false;
    }

    @Override
    public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
        return false;
    }

    @Override
    public void onLongPress(MotionEvent e) {

    }

    float rotateX;
    float rotateY;
    @Override
    public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {

        velocityX = velocityX>4000? 4000 : velocityX;
        velocityX = velocityX<-4000? -4000 : velocityX;
        velocityY = velocityY>4000? 4000 : velocityY;
        velocityY = velocityY<-4000? -4000 : velocityY;

        rotateX += velocityX*100/4000;
        rotateY += velocityY*100/4000;
        return true;
    }


    public void onTouch(MotionEvent event){
        switch(event.getAction()){
            case MotionEvent.ACTION_DOWN:
                touchX = event.getX();
                touchY = event.getY();
                break;
            case MotionEvent.ACTION_MOVE:
                rotateX += (event.getX()-touchX)/20;
                rotateY += ((event.getY()-touchY))/20;
                break;
            default:
                break;
        }
    }
}
